/* 
 *  Copyright 2012 CodeMagi, Inc.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  This product includes software developed by the
 *  Apache Software Foundation (http://www.apache.org/).
 *  The Apache Software Foundation in no way endorses or
 *  promotes this product.
 */
package com.codemagi.taglibs.input;

import com.codemagi.util.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.*;
import org.apache.log4j.*;

/**
 *  This class implements the &lt;input:checkbox&gt; tag, which presents an 
 *  &lt;input type="checkbox" ... /&gt; form element.
 *
 *  @version 1.0
 *  @author Shawn Bayern for Apache Software Foundation (Original Author)
 *  @author August Detlefsen for CodeMagi, Inc.
 */
public class Checkbox extends Input {

    static Logger log = Logger.getLogger("com.codemagi.taglibs.input.Checkbox");

    private String value;		// value of this particular button
    private boolean dVal;

    public void setValue(String x) {
	value = x;
    }

    public void setValue(Object x) {
	value = (x == null) ? "" : x.toString();
    }

    /**
     * Extra method to use a Boolean to set the default.
     *
     * @param x   new default value
     */
    public void setDefault(Boolean x) {
	log.debug("Checkbox.setDefault(Boolean) called with: " + x);
	
	if (x == null) {
	    dVal = false;
	} else {
	    dVal = x.booleanValue();
	}
    }

    /**
     * Extra method to use a boolean primitive to set the default.
     *
     * @param x   new default value
     */
    public void setDefault(boolean x) {
	log.debug("Checkbox.setDefault(boolean) called with: " + x);

	dVal = x;
    }

    /**
     *  Checkbox will be checked by default if the string argument is not null and is equal, ignoring case, to the string "true". 
     */
    public void setDefault(String x) {
	log.debug("Checkbox.setDefault(String) called with: " + x);

	dVal = new Boolean(x).booleanValue();
    }

    public int doStartTag() throws JspException {
	try {
            // sanity check
            if (name == null || name.equals(""))
                throw new JspTagException("invalid null or empty 'name'");
	    
	    // replace null value with "on"
	    if (value == null) value = "on";
	    
	    // get what we need from the page
	    ServletRequest req = pageContext.getRequest();

	    //generate the HTML tag
	    String html = getHtml(name, req, value, dVal, id, markupClass, attributes, override, disabled, showError);

	    //add HTML To the page 
	    JspWriter out = pageContext.getOut();
	    out.print(html);

	} catch (Exception ex) {
	    throw new JspTagException(ex.getMessage());
	}
	return SKIP_BODY;
    }


    public static String getHtml(String name, ServletRequest req, String value, boolean dVal, String id, String markupClass, Map attributes, boolean override, boolean disabled, boolean showError) 
	throws JspTagException {

	StringBuffer output = new StringBuffer(256);

	// start building up the tag
	output.append("<input ");
	output.append("    type=\"checkbox\"");
	output.append("    name=\"" + Util.quote(name) + "\"");
	output.append("    value=\"" + Util.quote(value) + "\"");
	if (!Utils.isEmpty(id)) {
	    output.append("    id=\"" + Util.quote(id) + "\"");
	}
	
	//disable the form field if disabled is set
	if (disabled) {
	    output.append("    disabled=\"disabled\"");
	    appendAttribute("OnClick", "return false;", attributes);
	}
	
	// include any attributes we've got here
	Util.printAttributes(output, attributes);
	
	/*
	 * Check this box (no pun intended) against potentially multiple
	 * selections.  (No need for a hash table as in <select> because
	 * we're doing this exactly once per tag.  We COULD cache stuff
	 * between tags, but I'm not sure that kind of extra performance
	 * would ever be called for.)  Note that we only use the
	 * "defaults" if the request is ENTIRELY empty; this is different
	 * from what we do with the other input types, checking "defaults"
	 * when there's no value for the specific field.  This difference
	 * is the result of the underlying inconsistency between checkboxes
	 * and everything else.
	 */
	String[] checked = getParameterValues(name, (HttpServletRequest)req);

	if ( Level.DEBUG.equals(log.getLevel()) ) {
	    log.debug("CHECKING REQUEST PARAMS");
	    Enumeration e = req.getParameterNames();
		while (e.hasMoreElements() ) {
		    log.debug("REQUEST PARAM: " + (String)e.nextElement());
		}
	}
	
	
	//OLD WAY:
	//checking to see if this is the first page hit
	//ie: the request is ENTIRELY empty
	//by: no elements in the request parameters
	//if (!req.getParameterNames().hasMoreElements()) {
	
	//NEW WAY: 
	//checking for the non-existence of the hidden input 
	String hiddenParam = getParameter("cb_" + name + "_cb", (HttpServletRequest)req);
	
	if ( override ) {
	    if (dVal) output.append("    checked=\"checked\"");
	    
	} else if (hiddenParam == null) {
	    log.debug("REQUEST PARAM: cb_" + name + "_cb NOT FOUND - new hit");
	    // use "default" if we got nothing from the request
	    if (dVal) output.append("    checked=\"checked\"");
	    
	} else if (checked != null) {
	    // use the request if it says anything
	    for (int i = 0; i < checked.length; i++)
		if (checked[i].equals(value)) {
		    output.append("    checked=\"checked\"");
		    break;					// why go on?
		}
	} 
	
	//if this is a required field and it is not filled out, do something...
	if ( !Utils.isEmpty((String)req.getAttribute("error_" + name + "_error")) ) {
	    output.append("    class=\"" + markupClass + " error\"");
	} else if ( !Utils.isEmpty(markupClass) ) {
	    output.append("    class=\"" + markupClass + "\"");
	}

	// end the tag
	output.append("/>");
	
	
	//show the error message
	if (showError) {
	    String errorMessage = (String)req.getAttribute(name + "_error_message");
	    if (errorMessage != null && !"".equals(errorMessage) ) {
		output.append( "<BR><SPAN CLASS=\"input_error_msg\">" + errorMessage + "</SPAN>");
	    }
	}
	
	//add a hidden input 
	//the presence of its value in the request parameters 
	//will indicate whether this is the first page hit
	output.append("<input type=\"hidden\" name=\"cb_" + name + "_cb\" value=\"1\" />");
	
	return output.toString();
    }
    
}
